///////////////////////////////////////////////
// This file is part of NoLifeStory.         //
// Please see Global.h for more information. //
///////////////////////////////////////////////
class PacketReader {
public:
	PacketReader(unsigned char * pbuffer, int len) : pos(0), length(len) { 
		buffer = pbuffer;
	}
	
	string ReadString();
	void Reset(int newpos);
	
	template<typename T>
	T Read();

	string ToString() const;
	int GetSize() const { return pos; }
	const unsigned char * GetBuffer() const { return buffer; }
	void Skip(int amount) { pos += amount; }
private:
	friend std::ostream & operator <<(std::ostream &out, const PacketReader &packet); // Thanks, Bui!

	unsigned char * buffer;
	int pos, length;
};

inline void PacketReader::Reset(int newpos) {
	if (length < pos) {
		string exc = "Trying to reset buffer position to ";
		exc += newpos + " while stream is only " + length;
		exc += " bytes long!"; // ?
		throw new exception(exc.c_str());
	}
	pos = newpos;
}


template<typename T>
T PacketReader::Read() {
	if (pos + sizeof(T) > length) throw "Unable to read  more bytes off the stream; end of stream!";
	T val = (*(T *)(buffer + pos));
	pos += sizeof(T);
	return val;
}

inline string PacketReader::ReadString() {
	short len = Read<short>();
	string ret = "";
	for (int i = 0; i < len; i++) {
		ret += Read<uint8_t>();
	}
	return ret;
}

inline
std::ostream & operator <<(std::ostream &out, const PacketReader &packet) {
	out << packet.ToString();
	return out;
}

inline
string PacketReader::ToString() const {
	string ret;
	if (length > 0) {
		std::stringstream out;
		const unsigned char *p = GetBuffer();
		size_t buflen = length - 1;
		for (size_t i = 0; i <= buflen; i++) {
			out << std::hex << std::uppercase << std::setw(2) << std::setfill('0') << static_cast<int16_t>(p[i]);
			if (i < buflen) {
				out << " ";
			}
		}
		ret = out.str();
	}
	return ret;
}